<template>
    <div>
        <el-table-column prop="rowKey" :width="width" :fixed="fixed" align="center">
            <!--  eslint-disable-next-line vue/no-unused-vars  -->
            <template slot="header" slot-scope="scope">
                <el-checkbox
                    v-model="selectAllBoxTemp"
                    :true-label="3"
                    :false-label="1"
                    :indeterminate="selectAllBoxTemp === 2"
                    @change="changeAll"
                />
                <el-dropdown v-if="showDropDown || showDropDown === ''" placement="bottom-start" trigger="click" @command="dropdownClick">
                    <span style="cursor: pointer">
                        <i class="el-icon-arrow-down el-icon--right"></i>
                    </span>
                    <el-dropdown-menu slot="dropdown">
                        <el-dropdown-item :command="item.value" v-for="item in dropDownList" :key="item.value">{{ item.text }}</el-dropdown-item>
                    </el-dropdown-menu>
                </el-dropdown>
            </template>
            <template slot-scope="scope">
                <el-checkbox
                    v-model="selectRowBoxTemp[scope.$index]"
                    :true-label="scope.row[rowKey]"
                    false-label=""
                    :disabled="disabledMethod(scope.row)"
                    @change="changeRow($event, scope)"
                    :key="scope.row[rowKey]"
                />
            </template>
        </el-table-column>
    </div>
</template>

<script lang="ts">
import { Component, Vue, Prop, Watch, Emit } from 'vue-property-decorator';
import { PropType } from 'vue';
import { isValidDate } from 'xe-utils/methods';

type fun = (row: any) => boolean;
enum selectAllValueState {
    empty = 1,
    indeterminate = 2,
    all = 3,
}

@Component({ name: 'TableSelection' })
export default class TableSelection extends Vue {
    // 宽度
    @Prop({ default: '55' }) readonly width!: string;
    // 是否固定表头
    @Prop({ default: true }) readonly fixed: boolean;
    // 是否显示下拉框
    @Prop({ default: false }) readonly showDropDown!: boolean | '';
    // 下拉框数据
    @Prop({
        default: () => [
            { text: '选择当前页', value: 'current' },
            { text: '选择所有页', value: 'all' },
        ],
    })
    readonly dropDownList!: { text: string; value: string }[];
    // 已选中的数据
    @Prop({ default: () => [] }) selected!: any[];
    // 当前页的表格数据
    @Prop({ default: () => [] }) readonly currentPageTableList!: any[];
    // 禁用条件
    @Prop({ default: () => false, type: Function as PropType<fun> }) readonly disabledMethod: fun;
    // 唯一 key
    @Prop({ default: 'key' }) readonly rowKey!: string;

    // 全选按钮
    selectAllBoxTemp: 1 | 2 | 3 = 1;
    // 全选按钮
    selectAllIndeterminate: boolean = false;
    // 表格中已选中的所有数据
    selectRowBoxTemp: any[] = [];
    // // 当前页的表格数据，组件内部使用
    // currentPageTableListTemp: any[] = [];

    // 监听所有已选择项变化，自动更新当前页的多选框勾选状态
    @Watch('selected', { deep: true, immediate: true })
    onWatchPropSelected(val: any[], oldVal: any[]) {
        // if (JSON.stringify(val) !== JSON.stringify(oldVal)) {
        //     const selected = JSON.parse(JSON.stringify(val));
        //     const currentPageTableList = JSON.parse(JSON.stringify(this.currentPageTableList));
        //     this.autoUpdateData(selected, currentPageTableList);
        // }
        const selected = JSON.parse(JSON.stringify(val));
        const currentPageTableList = JSON.parse(JSON.stringify(this.currentPageTableList));
        this.autoUpdateData(selected, currentPageTableList);
        console.log(val, 'val');
    }

    // 监听当前页面表格数据变化，自动更新当前页的多选框勾选状态
    @Watch('currentPageTableList', { deep: true })
    onWatchPropCurrentPageTableList(val: any[], oldVal: any[]) {
        // if (JSON.stringify(val) !== JSON.stringify(oldVal)) {
        //     const selected = JSON.parse(JSON.stringify(this.selected));
        //     const currentPageTableList = JSON.parse(JSON.stringify(val));
        //     this.autoUpdateData(selected, currentPageTableList);
        // }

        const selected = JSON.parse(JSON.stringify(this.selected));
        const currentPageTableList = JSON.parse(JSON.stringify(val));
        this.autoUpdateData(selected, currentPageTableList);
    }

    /**
     * 自动更新所有表格选中状态
     * @param selected 所有选中的数据
     * @param currentPageTableList 当前页面的所有数据
     */
    autoUpdateData(selected: any[], currentPageTableList: any[]) {
        const selectRowBoxTemp = currentPageTableList.map((item) => {
            const key = item[this.rowKey];
            if (selected.includes(key)) {
                return key;
            } else {
                return '';
            }
        });

        this.$set(this, 'selectRowBoxTemp', selectRowBoxTemp);

        // 修改全选状态
        const { state } = this.judgeSelectAllState(selected, currentPageTableList);
        this.$set(this, 'selectAllBoxTemp', state);
    }

    /**
     * 判断全选按钮的状态
     * @param selected 所有选中的数据
     * @param currentPageTableList 当前页面表格数据
     */
    judgeSelectAllState(selected: any[], currentPageTableList: any[]) {
        const selectRowBoxTemp = currentPageTableList.map((item) => {
            const key = item[this.rowKey];
            if (selected.includes(key)) {
                return key;
            } else {
                return '';
            }
        });
        // 判断全选按钮的状态
        // 1. 获取当前页所有未禁用的多选框
        const optionalAll = [];
        currentPageTableList.forEach((item) => {
            const isDisabled = this.disabledMethod(item);
            if (!isDisabled) {
                optionalAll.push(item[this.rowKey]);
            }
        });
        // 2. 获取当前页未禁用多选框中已选择的数据
        const optionalSelected = selectRowBoxTemp.filter((item) => {
            // 当数据不为空，并且在当前页的可选项内，就返回这一项
            return !!item && optionalAll.includes(item);
        });

        let state: 1 | 2 | 3;
        if (!optionalAll.length || !optionalSelected.length) {
            state = selectAllValueState.empty;
        } else if (optionalSelected.length === optionalAll.length) {
            state = selectAllValueState.all;
        } else {
            state = selectAllValueState.indeterminate;
        }
        return {
            // 当前页所有未禁用的多选框
            optionalAll,
            // 当前页未禁用多选框中已选择的数据
            optionalSelected,
            // 当前全选按钮的状态
            state,
        };
    }

    /**
     * 全选框
     */
    changeAll(value) {
        const { optionalAll, optionalSelected } = this.judgeSelectAllState(this.selected, this.currentPageTableList);
        if (value === selectAllValueState.all || value === selectAllValueState.indeterminate) {
            // 添加当前页还没选中的项
            const addData = optionalAll.filter((item) => !optionalSelected.includes(item));
            this.selected.push(...addData);
            this.autoUpdateData(this.selected, this.currentPageTableList);
        } else if (value === selectAllValueState.empty) {
            // 删除当前页已经选中的项
            const len = this.selected.length;
            const delData = optionalSelected;
            for (let i = len; i >= 0; i--) {
                if (optionalSelected.includes(this.selected[i])) {
                    this.selected.splice(i, 1);
                }
            }

            this.autoUpdateData(this.selected, this.currentPageTableList);
        }
        this.$emit('getSelected', this.selected);
    }

    /**
     * 点击表格行的多选框
     * @param value 当前行的选中状态
     * @param row 当前行数据
     */
    changeRow(value, row) {
        console.log(row, 'row');

        const rowKey = row.row[this.rowKey];
        if (value === '') {
            const index = this.selected.indexOf(rowKey);
            if (index > -1) {
                this.selected.splice(index, 1);
                const { state } = this.judgeSelectAllState(this.selected, this.currentPageTableList);
                this.$set(this, 'selectAllBoxTemp', state);
            }
        } else {
            this.selected.push(rowKey);
            const { state } = this.judgeSelectAllState(this.selected, this.currentPageTableList);
            this.$set(this, 'selectAllBoxTemp', state);
        }
        this.$emit('getSelected', this.selected);
    }

    @Emit()
    dropdownClick(command: string) {
        return command;
    }
}
</script>

<style scoped lang="scss"></style>
